import type { Line } from '../index.d';

export type ColorPreset = {
  [key: string]: string | number[]; // 支持hex/rgb/rgba/数组格式
};

// 定义颜色预设
export const COLOR_PRESETS = {
  idle: 'rgba(82, 196, 26, 0.8)',
  busy: 'rgba(250, 173, 20, 0.8)', // 忙碌状态-橙色
  fault: 'rgba(245, 34, 45, 0.8)',
  normal: 'rgba(82, 196, 26, 0.8)', // 正常状态-绿色
  offline: 'rgba(151, 151, 151, 0.8)', // 离线状态-灰色
  disable: 'rgba(151, 151, 151, 0.8)',
};

async function imageBitmapToBase64(
  bitmap: ImageBitmap,
  format = 'image/png',
): Promise<string> {
  const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
  const ctx = canvas.getContext('2d');
  if (!ctx) throw new Error('Canvas context initialization failed');

  ctx.drawImage(bitmap, 0, 0);
  const blob = await canvas.convertToBlob({ type: format });
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.readAsDataURL(blob);
  });
}

/**
 * 批量生成不同颜色的ImageBitmap
 * @param {ImageBitmap} imageBitmap - 原始图像
 * @param {ColorPreset} colors - 颜色预设集（如：{error: '#ff0000', normal: '#00ff00'}）
 * @param {number} [mixRatio=1] - 混合比例（0-1）
 * @returns {Promise<Record<string, ImageBitmap|string>>} 颜色名称与处理后的ImageBitmap映射
 */
export async function addColoredIcons(
  imageBitmap: ImageBitmap,
  colors: ColorPreset,
  mixRatio = 1,
  type: 'circle' | 'roundRect' | 'circle_dark' | 'roundRect_dark' | null = null,
): Promise<Record<string, ImageBitmap | string>> {
  // 1. 颜色标准化统一处理
  const normalizeColor = (
    color: string | number[],
  ): [number, number, number] => {
    if (Array.isArray(color))
      return color.slice(0, 3) as [number, number, number];

    if (typeof color === 'string') {
      // Hex颜色处理（兼容#RGB和#RRGGBB）
      if (color.startsWith('#')) {
        const hex =
          color.length === 4
            ? color.replace(/^#(.)(.)(.)$/, '#$1$1$2$2$3$3')
            : color;
        return [
          Number.parseInt(hex.substring(1, 3), 16),
          Number.parseInt(hex.substring(3, 5), 16),
          Number.parseInt(hex.substring(5, 7), 16),
        ];
      }
      // RGB/RGBA字符串处理
      if (color.startsWith('rgb')) {
        const values = color.match(/\d+/g)?.slice(0, 3).map(Number) || [];
        return values.length === 3
          ? (values as [number, number, number])
          : [255, 255, 255];
      }
    }
    throw new Error(`Invalid color format: ${color}`);
  };

  // 2. 创建Canvas处理原始图像（复用同一Canvas提升性能）
  const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height);
  const ctx = canvas.getContext('2d', { willReadFrequently: true });
  if (!ctx) throw new Error('Canvas context initialization failed');
  ctx.drawImage(imageBitmap, 0, 0);
  const originalData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  // 3. 批量生成处理结果
  const results: Record<string, ImageBitmap | string> = {};
  await Promise.all(
    Object.entries(colors).map(async ([name, color]) => {
      // 克隆原始像素数据避免污染
      const imageData = new ImageData(
        new Uint8ClampedArray(originalData.data),
        originalData.width,
        originalData.height,
      );
      const data = imageData.data;
      const targetColor = normalizeColor(color);

      // 颜色混合算法（保留Alpha通道）
      for (let i = 0; i < data.length; i += 4) {
        if (data[i + 3] > 0) {
          // 仅处理非透明像素
          for (let c = 0; c < 3; c++) {
            data[i + c] = Math.round(
              data[i + c] * (1 - mixRatio) + targetColor[c] * mixRatio,
            );
          }
        }
      }

      // 输出处理结果
      ctx.putImageData(imageData, 0, 0);
      // 绘制边框
      if (type) {
        ctx.strokeStyle = type.endsWith('_dark') ? '#f0f0f0' : '#202020';
        ctx.lineWidth = 1;
        type.includes('roundRect')
          ? drawRoundRect(ctx, 1, 1, canvas.width - 2, canvas.height - 2, 2)
          : drawCircle(
              ctx,
              canvas.width / 2.0,
              canvas.height / 2.0,
              canvas.width / 2.0 - 1,
            );
      }

      results[name] = await createImageBitmap(canvas);
      // TODO 后续考虑是否需要将结果转换为Base64格式、性能问题
      results[`dataurl_${name}`] = await imageBitmapToBase64(results[name]);
    }),
  );
  return results;
}

function drawRoundRect(
  ctx: OffscreenCanvasRenderingContext2D,
  x: number,
  y: number,
  width: number,
  height: number,
  radius: number,
) {
  ctx.beginPath();
  ctx.moveTo(x + radius, y);
  ctx.lineTo(x + width - radius, y);
  ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  ctx.lineTo(x + width, y + height - radius);
  ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  ctx.lineTo(x + radius, y + height);
  ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  ctx.lineTo(x, y + radius);
  ctx.quadraticCurveTo(x, y, x + radius, y);
  ctx.closePath();
  ctx.stroke();
}

function drawCircle(
  ctx: OffscreenCanvasRenderingContext2D,
  x: number,
  y: number,
  radius: number,
) {
  ctx.beginPath();
  // ctx.arc(x, y, radius, 0, 2 * Math.PI);
  ctx.ellipse(x, y, radius, radius, Math.PI / 4, 0, 2 * Math.PI);
  ctx.closePath();
  ctx.stroke();
}

export function createIconElement(url: string): HTMLElement {
  const el = document.createElement('div');
  el.className = 'custom-marker';
  el.style.backgroundImage = `url(${url})`;
  el.style.backgroundSize = 'contain';
  el.style.backgroundRepeat = 'no-repeat';
  el.style.width = '32px';
  el.style.height = '32px';
  el.style.opacity = '1';
  el.style.zIndex = '100';
  return el;
}

export function getTextOffsetDistance(zoom: number | undefined): number {
  if (!zoom) return 0;

  // 定义关键点
  const points = [
    { zoom: 8, value: 10000 },
    { zoom: 10, value: 4000 },
    { zoom: 12, value: 1500 },
    { zoom: 15, value: 800 },
    { zoom: 18, value: 200 },
  ];

  // 找到当前zoom所在的区间
  for (let i = 0; i < points.length - 1; i++) {
    if (zoom >= points[i].zoom && zoom <= points[i + 1].zoom) {
      // 线性插值计算
      const ratio =
        (zoom - points[i].zoom) / (points[i + 1].zoom - points[i].zoom);
      return points[i].value + (points[i + 1].value - points[i].value) * ratio;
    }
  }

  // 超出范围时返回边界值
  return zoom < points[0].zoom
    ? points[0].value
    : points[points.length - 1].value;
}

export function calculateNextPoint(
  p1: [number, number],
  angle: number,
  length: number,
) {
  // 将角度转换为弧度
  const radians = (angle * Math.PI) / 180;
  // 计算终点坐标
  const earthRadius = 6378137; // 地球半径(米)
  const distance = length / earthRadius;

  const lat1 = (Number(p1[1]) * Math.PI) / 180;
  const lng1 = (Number(p1[0]) * Math.PI) / 180;

  const lat2 = Math.asin(
    Math.sin(lat1) * Math.cos(distance) +
      Math.cos(lat1) * Math.sin(distance) * Math.cos(radians),
  );

  const lng2 =
    lng1 +
    Math.atan2(
      Math.sin(radians) * Math.sin(distance) * Math.cos(lat1),
      Math.cos(distance) - Math.sin(lat1) * Math.sin(lat2),
    );

  return [
    (lng2 * 180) / Math.PI, // 经度
    (lat2 * 180) / Math.PI, // 纬度
  ];
}

export function calculateEndPoint(line: Line): [number, number] {
  const angle = line.azimuth || 0;
  // 将角度转换为弧度
  const radians = (angle * Math.PI) / 180;
  // 计算终点坐标
  const earthRadius = 6378137; // 地球半径(米)
  const distance = line.lineLength / earthRadius;

  const lat1 = (Number(line.latitude) * Math.PI) / 180;
  const lng1 = (Number(line.longitude) * Math.PI) / 180;

  const lat2 = Math.asin(
    Math.sin(lat1) * Math.cos(distance) +
      Math.cos(lat1) * Math.sin(distance) * Math.cos(radians),
  );

  const lng2 =
    lng1 +
    Math.atan2(
      Math.sin(radians) * Math.sin(distance) * Math.cos(lat1),
      Math.cos(distance) - Math.sin(lat1) * Math.sin(lat2),
    );

  return [
    (lng2 * 180) / Math.PI, // 经度
    (lat2 * 180) / Math.PI, // 纬度
  ];
}

/**
 * 安全地从options对象中获取属性值
 * @param key 要获取的属性名
 * @param options 配置对象
 * @param defaultValue 默认值
 * @returns 属性值或默认值
 */
export function getOption<T>(
  key: string,
  options: unknown,
  defaultValue: T,
): T {
  return typeof options === 'object' && options !== null && key in options
    ? (options as Record<string, T>)[key]
    : defaultValue;
}

export function toNumber(value: string | number): number {
  return typeof value === 'string' ? Number(value) : value;
}
